package com.xiyuan.smartutils.client.ws.core;

import com.xiyuan.smartutils.Files;
import com.xiyuan.smartutils.client.ws.WebSocketPacket;
import com.xiyuan.smartutils.client.exception.WebSocketException;
import com.xiyuan.smartutils.client.ws.core.impl.rfc6455.DefaultWebsocketPacket;

import java.nio.ByteBuffer;

/**
 * the description for class WebSocketPacketDefaultParser
 *
 * @author xiyuan-lgz 2024-10-29 @version v1.0.0 新建与整理
 */
public class DefaultWebSocketPacketResolver extends WebSocketPacketResolver {
    private final BufferManager bufferManager = new BufferManager();
    private volatile WebsocketPacketHeader header = null;
    
    @Override
    public void reset() {
        bufferManager.reset();
    }
    @Override
    public WebSocketPacket resolve(ByteBuffer appBuffer) throws WebSocketException {
        if (!appBuffer.hasRemaining()) {return null;}
        
        ByteBuffer buffer = null;
        if (PacketState.DONE.equals(this.state())) {
            // 上次 解析 完毕需要切换为重新解析状态
            this.stateTo(PacketState.HEADER);
            buffer = appBuffer;
            header = null;
        }
        else {// get and merge Fragmented buffer
            buffer = bufferManager.merge(appBuffer);
        }
        
        // parse packet header
        if (PacketState.HEADER.equals(this.state())) {
            int pos = buffer.position();
            this.header = WebsocketPacketHeader.parseHeader(buffer, this.header);
            if (header == null) {
                // the header bytes is not ready.
                buffer.position(pos);
                this.bufferManager.storeFragmentBuffer(buffer);
                return null;
            }
            
            if (this.header.getPayloadLength() - 1 > Integer.MAX_VALUE) {
                throw new IllegalArgumentException("large data is not support yet");
            }
            
            // header parse finished
            this.stateTo(PacketState.FRAME);
        }
        
        // parse packet data
        int payloadLen = (int) header.getPayloadLength();
        if (PacketState.FRAME.equals(this.state())) {
            
            if (payloadLen > buffer.remaining()) {
                // the packet bytes is not ready.
                this.bufferManager.storeFragmentBuffer(buffer);
                return null;
            }
            
            byte[] body = new byte[payloadLen];
            buffer.get(body, 0, payloadLen);
            this.stateTo(PacketState.DONE);
            this.bufferManager.reset();// reset
            return new DefaultWebsocketPacket(body, header);
        }
        
        return null;
    }
    
    public static void main(String[] args) {
        
        WebSocketPacket packet = new DefaultWebsocketPacket("hello word");
        packet.mask();
        Files.write("D:/data/ws-packet", packet.toByteBuffer().array());
    }
}
